﻿#include "crc32.h"

static unsigned long   s_CRC32Table[256];
static unsigned long crc32_bit_reverse(unsigned long ulValue, int iBits)
{
	int   i;
	unsigned long ulTemp = ulValue;

	for (i = 0; i < iBits; i++)
	{
		if (ulTemp & 1L)
		{
			ulValue |= (1L << ((iBits - 1) - i));
		}
		else
		{
			ulValue &= ~(1L << ((iBits - 1) - i));
		}
		ulTemp >>= 1;
	}
	return ulValue;
}

static unsigned long crc32_generate_element(unsigned short nIndex, unsigned char nWidth, unsigned long dwPoly, unsigned char isReversed)
{
	// nWidth: Width in bits [8,32]
	// dwPoly: The algorithm's polynomial
	int   i;
	unsigned long dwRetValue;
	unsigned long dwTopBit = (1L << (nWidth - 1));
	unsigned long dwIndexedByte = (unsigned long)nIndex;

	if (isReversed)
		dwIndexedByte = crc32_bit_reverse(dwIndexedByte, 8);
	dwRetValue = dwIndexedByte << (nWidth - 8);
	for (i = 0; i < 8; i++)
	{
		if (dwRetValue & dwTopBit)
			dwRetValue = (dwRetValue << 1) ^ dwPoly;
		else
			dwRetValue <<= 1;
	}
	if (isReversed)
		dwRetValue = crc32_bit_reverse(dwRetValue, nWidth);
	return dwRetValue;
}

void crc32_genearte_table(void* pvTable, unsigned short nSize, unsigned char nWidth, unsigned long dwPoly, unsigned char isReversed)
{
	unsigned short i;
	unsigned long element;
	if (nWidth != 16 && nWidth != 32)
	{
		return;
	}
	for (i = 0; i < nSize; i++)
	{
		element = crc32_generate_element(i, nWidth, dwPoly, isReversed);
		if (nWidth == 16)
			*((unsigned short*)pvTable + i) = (unsigned short)element;
		else if (nWidth == 32)
			*((unsigned long*)pvTable + i) = element;
	}
}

unsigned long calc_file_crc(void* pvData, unsigned long dwSize)
{
	unsigned long  dwCRC32;
	unsigned char *pbData = (unsigned char*)pvData;

	if (s_CRC32Table[1] != 0x77073096L)
		crc32_genearte_table(s_CRC32Table, 256, 32, 0x04C11DB7L, 1);

	dwCRC32 = 0xffffffffL;
	while (dwSize--)
		dwCRC32 = s_CRC32Table[(dwCRC32 ^ *pbData++) & 0xFFL] ^ (dwCRC32 >> 8);
	return dwCRC32 ^ 0xffffffffL;
}
